import { consts } from "@/module-00-codebase/pkg-00-const";
import { Bi, Pi } from "@/module-00-codebase/pkg-01-container";
import { PendingPromise, pendingResolve, Throwable } from "@/module-00-codebase/pkg-02-tool";
import { BasePage } from "@/module-00-codebase/pkg-03-abstract";

type Ta = { target: string; args: any; promise: PendingPromise<void>; isReplace: boolean };
const pageCaches: Ta[] = [];
let isForwarding = false;
export class ReactNavigate {
  public async replace(target: string, args?: any) {
    return this.forward(`replace:${target}`, args);
  }
  public async forward(target: string, args?: any) {
    let isReplace = false;
    if ((isReplace = target.indexOf("replace:") === 0)) {
      target = target.substring("replace:".length);
    }
    if (target[0] !== "/") {
      const currentPath = this.getCurrentRoutePath();
      const preFixPath = currentPath !== "/" ? `${currentPath}/` : currentPath;
      target = `${preFixPath}${target}`;
    }
    const pending = pendingResolve<void>();
    // 1. cache arguments
    pageCaches.push({ target: target, args: args, promise: pending, isReplace });
    if (!isForwarding && (isForwarding = true)) {
      try {
        Bi.loading.on();
        let ta: Ta | undefined;
        const tas = [] as Ta[];
        while (pageCaches.length > 0 && !!(ta = pageCaches.shift())) {
          const Page = Pi[ta.target];
          if (!Page) Throwable("Page not found: " + ta.target);
          Bi.log.debug(`prepare page ${ta.target}`);
          Page.prototype.setArgs(ta.args);
          await Page.prototype.proxyPageInit(Page.prototype.getArgs());
          tas.push(ta);
        }
        for (let i = 0; i < tas.length; i++) {
          const ta = tas[i];
          Bi.log.debug(`push: ${ta.target}`);
          if (this.getCurrentRoutePath() !== ta.target) {
            if (ta.isReplace) {
              Bi.historyFactory.replace(ta.target);
            } else {
              Bi.historyFactory.push(ta.target);
            }
          }
        }
        for (let i = 0; i < tas.length; i++) {
          tas[i].promise.resolve();
        }
      } catch (ex) {
        const e = ex instanceof Error ? ex : new Error(JSON.stringify(ex));
        Bi.loading.on(e.message, consts.error_loading_ms);
      } finally {
        isForwarding = false;
        Bi.loading.off();
      }
    }
    return pending;
  }
  public back(): void {
    Bi.historyFactory.back();
  }
  public getCurrentRoutePath(): string {
    return Bi.historyFactory.getCurrentRoute();
  }
  public getCurrentPage() {
    const page = pageCache.get(this.getCurrentRoutePath());
    if (!page) {
      throw new Error(`Impossible Error: Page [${this.getCurrentRoutePath()}] does not exists.`);
    } else {
      return page;
    }
  }
  public setCurrentPage(page: BasePage) {
    pageCache.set(page.pageRoutePath(), page);
  }
}
const pageCache = new Map<string, BasePage>();
